const net = require('net');

const SERVER_HOST = 'gitserver'; // Your server's IP
const SERVER_PORT = 12345;   // Your server's port
const NUM_CONNECTIONS = 7000; // Number of concurrent connections to create
const MESSAGES_PER_CONNECTION = 20; // How many messages each connection sends
const MESSAGE_INTERVAL_MS = 100; // Delay between messages (per connection)
const MESSAGE_PREFIX = 'StressTestMessage-'; // Prefix for messages

let activeConnections = 0;
let successfulConnections = 0;
let failedConnections = 0;
let totalMessagesSent = 0;
let totalMessagesReceived = 0;
let totalResponseTime = 0; // in milliseconds
let testStartTime;

console.log(`Starting TCP stress test with ${NUM_CONNECTIONS} connections...`);

function createClient(connectionId) {
    const client = new net.Socket();
    let messagesSent = 0;
    let responseTimes = [];
    let messageCounter = 0;

    client.connect(SERVER_PORT, SERVER_HOST, () => {
        activeConnections++;
        successfulConnections++;
        // console.log(`[Conn ${connectionId}] Connected. Active: ${activeConnections}`);
        sendMessage();
    });

    client.on('data', (data) => {
        totalMessagesReceived++;
        const message = data.toString();
        // console.log(`[Conn ${connectionId}] Received: "${message}"`);

        // Measure response time if we track start times
        const endTime = process.hrtime.bigint();
        const startTime = client._messageStartTime; // Stored when message was sent
        if (startTime) {
            const duration = Number(endTime - startTime) / 1_000_000; // Convert nanoseconds to milliseconds
            responseTimes.push(duration);
            totalResponseTime += duration;
            delete client._messageStartTime; // Clean up
        }


        if (messagesSent < MESSAGES_PER_CONNECTION) {
            setTimeout(sendMessage, MESSAGE_INTERVAL_MS);
        } else {
            // All messages sent and received for this connection
            client.end();
        }
    });

    client.on('end', () => {
        // console.log(`[Conn ${connectionId}] Disconnected.`);
    });

    client.on('error', (err) => {
        // console.error(`[Conn ${connectionId}] Client error: ${err.message}`);
        if (!client._hasErrored) { // Prevent double counting if 'error' and 'close' both fire for same issue
            failedConnections++;
            client._hasErrored = true; // Mark as errored
        }
    });

    client.on('close', (hadError) => {
        activeConnections--;
        // console.log(`[Conn ${connectionId}] Connection closed. Active: ${activeConnections}`);
        if (activeConnections === 0 && (totalMessagesSent === NUM_CONNECTIONS * MESSAGES_PER_CONNECTION)) {
            // All connections processed and messages sent/received
            reportResults();
        }
    });

    function sendMessage() {
        if (!client.writable) {
            // console.log(`[Conn ${connectionId}] Socket not writable, skipping send.`);
            return;
        }
        const message = `${MESSAGE_PREFIX}${messageCounter++}`;
        client.write(message);
        totalMessagesSent++;
        client._messageStartTime = process.hrtime.bigint(); // Store start time for response calculation
        messagesSent++;
        // console.log(`[Conn ${connectionId}] Sent: "${message}". Total sent: ${totalMessagesSent}`);
    }
}

// Start the test
testStartTime = Date.now();
for (let i = 0; i < NUM_CONNECTIONS; i++) {
    createClient(i);
}

function reportResults() {
    const testDuration = (Date.now() - testStartTime) / 1000; // in seconds
    const averageResponseTime = totalMessagesReceived > 0 ? (totalResponseTime / totalMessagesReceived).toFixed(2) : 'N/A';
    const messagesPerSecond = testDuration > 0 ? (totalMessagesSent / testDuration).toFixed(2) : 'N/A';
    const receivedMessagesPerSecond = testDuration > 0 ? (totalMessagesReceived / testDuration).toFixed(2) : 'N/A';

    console.log('\n--- Stress Test Results ---');
    console.log(`Total duration: ${testDuration} seconds`);
    console.log(`Attempted connections: ${NUM_CONNECTIONS}`);
    console.log(`Successful connections: ${successfulConnections}`);
    console.log(`Failed connections: ${failedConnections}`);
    console.log(`Total messages sent: ${totalMessagesSent}`);
    console.log(`Total messages received: ${totalMessagesReceived}`);
    console.log(`Average response time per message: ${averageResponseTime} ms`);
    console.log(`Messages sent per second: ${messagesPerSecond}`);
    console.log(`Messages received per second: ${receivedMessagesPerSecond}`);
    console.log('---------------------------\n');
    process.exit(0); // Exit process after reporting
}

// Set a timeout to report results even if some connections hang
setTimeout(() => {
    console.warn('\n--- Test timeout reached! Reporting partial results ---');
    reportResults();
}, (MESSAGE_INTERVAL_MS * MESSAGES_PER_CONNECTION * 2) + 10000); // Adjust timeout as needed